
#include <cecore/cefile.h>
#include <cegfx/cematerialmanager.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <assert.h>

ceMaterialManager* ceMaterialManager::static_instance = 0;

ceMaterialManager::ceMaterialManager (LPDIRECT3DDEVICE9 device)
	: device (device)
{
}

ceMaterialManager::~ceMaterialManager ()
{
}


ceMaterialManager* ceMaterialManager::Get ()
{
	if (!ceMaterialManager::static_instance)
	{
		ceMaterialManager::static_instance = new ceMaterialManager (0);
	}
	return ceMaterialManager::static_instance;
}


ceMaterialManager* ceMaterialManager::Initialize (LPDIRECT3DDEVICE9 device)
{
	ceMaterialManager* mgr = ceMaterialManager::Get ();
	mgr->device = device;
	return mgr;
}

ceMaterialManager* ceMaterialManager::Initialize (ceMaterialManager* manager)
{
	if (ceMaterialManager::static_instance)
	{
		delete ceMaterialManager::static_instance;
	}

	ceMaterialManager::static_instance = manager;
	return manager;
}

void ceMaterialManager::AddTexture (const ceString& name, LPDIRECT3DTEXTURE9 texture)
{
	assert (texture != 0);

	TextureData data;
	ZeroMemory (&data, sizeof (TextureData));
	data.Name = name;
	data.Texture = texture;
	texture->AddRef ();

	textures.push_back (data);
}

void ceMaterialManager::AddEffect (const ceString& name, ceEffect* effect)
{
	assert (effect != 0);
	EffectData data;
	ZeroMemory (&data, sizeof (EffectData));
	data.Name = name;
	data.Effect = effect;

	effect->AddRef();

	effects.push_back (data);
}


void ceMaterialManager::AddMaterial (const ceString& name, ceMaterial* material)
{
	assert (material);
	MaterialData data;
	ZeroMemory (&data, sizeof (MaterialData));
	data.Name = name;
	data.Material = material;
	material->AddRef ();

	materials.push_back (data);
}


void ceMaterialManager::RemoveTexture (const ceString& name)
{
	std::list<TextureData>::iterator it;
	for (it = textures.begin (); it != textures.end (); it++)
	{
		if (it->Name == name)
		{
			if (it->Texture)
			{
				it->Texture->Release();
			}
			textures.erase (it);
			return;
		}
	}
}

void ceMaterialManager::RemoveEffect (const ceString& name)
{
	std::list<EffectData>::iterator it;
	for (it = effects.begin (); it != effects.end (); it++)
	{
		if (it->Name == name)
		{
			if (it->Effect)
			{
				it->Effect->Release();
			}
			effects.erase (it);
			return;
		}
	}
}


void ceMaterialManager::RemoveMaterial (const ceString& name)
{
	std::list<MaterialData>::iterator it;
	for (it = materials.begin (); it != materials.end (); it++)
	{
		if (it->Name == name)
		{
			if (it->Material)
			{
				it->Material->Release();
			}
			materials.erase (it);
			return;
		}
	}
}

void ceMaterialManager::RegisterTexture (const ceString& name, const ceString& filename)
{
	TextureData data;
	ZeroMemory (&data, sizeof (TextureData));
	data.Name = name;
	data.Filename = filename;

	textures.push_back (data);
}

void ceMaterialManager::RegisterEffect (const ceString& name, const ceString& filename)
{
	EffectData data;
	ZeroMemory (&data, sizeof (EffectData));
	data.Name = name;
	data.Filename = filename;

	effects.push_back (data);
}

void ceMaterialManager::RegisterMaterial (const ceString& filename)
{
	iFile* file = openFile (filename);
	if (!file)
	{
		return;
	}
	iMaterialLoader* loader = getMaterialLoader (file);
	if (!loader)
	{
		file->Release ();
		return;
	}

	ceString name = loader->LoadName (file);
	if (name.length () != 0)
	{
		RegisterMaterial (name, filename);
	}

	file->Release ();
}

void ceMaterialManager::RegisterMaterial (const ceString& name, const ceString& filename)
{
	MaterialData data;
	ZeroMemory (&data, sizeof (MaterialData));
	data.Name = name;
	data.Filename = filename;

	materials.push_back (data);
}

bool ceMaterialManager::HasTexture (const ceString& name) const
{
	std::list<TextureData>::const_iterator it;
	for (it = textures.begin (); it != textures.end (); it++)
	{
		if (it->Name == name)
		{
			return true;
		}
	}
	return false;
}

bool ceMaterialManager::HasEffect (const ceString& name) const
{
	std::list<EffectData>::const_iterator it;
	for (it = effects.begin (); it != effects.end (); it++)
	{
		if (it->Name == name)
		{
			return true;
		}
	}
	return false;
}

bool ceMaterialManager::HasMaterial (const ceString& name) const
{
	std::list<MaterialData>::const_iterator it;
	for (it = materials.begin (); it != materials.end (); it++)
	{
		if (it->Name == name)
		{
			return true;
		}
	}
	return false;
}

LPDIRECT3DTEXTURE9 ceMaterialManager::GetTexture (const ceString& name)
{
	std::list<TextureData>::iterator it;
	for (it = textures.begin (); it != textures.end (); it++)
	{
		if (it->Name == name)
		{
			if (!it->Texture)
			{
				iFile* file = openFile (it->Filename);
				if (!file)
				{
					return 0;
				}
				iTextureLoader* loader = getTextureLoader (file);
				if (loader)
				{
					it->Texture = loader->Load (device, file);
					if (it->Texture)
					{
						it->Texture->AddRef ();
					}
				}
				file->Release ();
			}
			return it->Texture;
		}
	}
	return 0;
}
ceEffect* ceMaterialManager::GetEffect (const ceString& name)
{
	std::list<EffectData>::iterator it;
	for (it = effects.begin (); it != effects.end (); it++)
	{
		if (it->Name == name)
		{
			if (!it->Effect)
			{
				iFile* file = openFile (it->Filename);
				if (!file)
				{
					return 0;
				}
				iEffectLoader* loader = getEffectLoader(file);
				if (loader)
				{
					it->Effect = loader->Load (device, file);
					if (it->Effect)
					{
						it->Effect->AddRef ();
					}
				}
				file->Release ();
			}
			return it->Effect;
		}
	}
	return 0;
}

ceMaterial* ceMaterialManager::GetMaterial (const ceString& name)
{
	std::list<MaterialData>::iterator it;
	for (it = materials.begin (); it != materials.end (); it++)
	{
		if (it->Name == name)
		{
			if (!it->Material)
			{
				iFile* file = openFile (it->Filename);
				if (!file)
				{
					return 0;
				}
				iMaterialLoader* loader = getMaterialLoader (file);
				if (loader)
				{
					it->Material = loader->Load (device, file);
					if (it->Material)
					{
						it->Material->AddRef ();
					}
				}
				file->Release ();
			}
			return it->Material;
		}
	}
	return 0;
}


iFile* ceMaterialManager::openFile (const ceString& filename)
{
	ceFile* file = new ceFile (filename);
	if (file->Open (iFile::OM_Read))
	{
		return file;
	}

	file->Release ();

	return 0;
}


iTextureLoader* ceMaterialManager::getTextureLoader (iFile* file)
{
	std::list<iTextureLoader*>::iterator it;
	for (it = textureLoader.begin (); it != textureLoader.end (); it++)
	{
		if ((*it)->CanLoad (file))
		{
			return *it;
		}
	}
	return 0;
}

iEffectLoader* ceMaterialManager::getEffectLoader (iFile* file)
{
	std::list<iEffectLoader*>::iterator it;
	for (it = effectLoader.begin (); it != effectLoader.end (); it++)
	{
		if ((*it)->CanLoad (file))
		{
			return *it;
		}
	}
	return 0;
}

iMaterialLoader* ceMaterialManager::getMaterialLoader (iFile* file)
{
	std::list<iMaterialLoader*>::iterator it;
	for (it = materialLoader.begin (); it != materialLoader.end (); it++)
	{
		if ((*it)->CanLoad (file))
		{
			return *it;
		}
	}
	return 0;
}


void ceMaterialManager::AddTextureLoader (iTextureLoader* loader)
{
	textureLoader.push_back (loader);
}

void ceMaterialManager::AddEffectLoader (iEffectLoader* loader)
{
	effectLoader.push_back (loader);
}

void ceMaterialManager::AddMaterialLoader (iMaterialLoader* loader)
{
	materialLoader.push_back (loader);
}
